/**
* Base Model will be extended by all components. This class has utility methods and variables which are required at a framework level.
* This file specifies all those functions which are dependent on [KnockoutJS]{@link http://knockoutjs.com}.
* @module baseModel
* @requires jquery
* @requires knockout
* @requires ojs/ojcore
* @requires base-model
* @requires knockout-mapping
* @requires base-models/validations/validations
* @requires base-models/ko/formatters
* @requires base-models/ko/help
* @requires base-models/ko/custom-bindings
* @requires knockout-helper
* @requires framework/js/constants/constants
* @requires extensions/extension.json
*/
define([
"ojs/ojcore",
"knockout",
"jquery",
"base-model",
"base-models/validations/validations",
"base-models/ko/help",
"ojL10n!resources/nls/generic",
"framework/js/constants/constants",
"text!extensions/extension.json",
"base-models/ko/custom-bindings",
"knockout-helper",
"ojs/ojknockout"
], function (oj, ko, $, BaseModel, Validations, Help, Locale, Constants, extensions, jsonCallBack) {
"use strict";
/**
* Base Model will be extended by all components. This class has utility methods and variables which are required at a framework level.
* This file specifies all those functions which are dependent on [KnockoutJS]{@link http://knockoutjs.com}.
* @class
* @alias BaseKOModel
* @memberof module:baseModel
*/
var BaseKOModel = function () {
/**
* Assign this to self.
* @member {Object}
*/
var self = this;
ko.utils.extend(self, new BaseModel());
ko.utils.extend(self, new Validations());
ko.utils.extend(self, new Help(self));
/**
* This variable hold the object for current extentions.
* @type {Object}
*/
var Extensions = JSON.parse(extensions);
// ======================= SCB ========================
self.checkAndShowError = function (data) {
//1.
if (data == null || data.status == null) {
return false;
}
//validate error
if (data.responseJSON != null && data.responseJSON.message != null) {
if (data.responseJSON.message.validationError != null &&
data.responseJSON.message.validationError.length > 0 &&
data.responseJSON.message.validationError[0] != null &&
data.responseJSON.message.validationError[0].errorMessage != null) {
var errorCode = data.responseJSON.message.validationError[0].errorCode;
if (errorCode == "DIGX_FU_048" || errorCode == "DIGX_AUTH_0013" || errorCode =="DIGX_SCB_GEN_500") {
self.showMessages(data, null, null, function () {
history.back();
window.onbeforeunload = null;
});
return true;
} else {
self.showMessages(null, [data.responseJSON.message.validationError[0].errorMessage], 'ERROR');
return true;
}
} else {
var messageCode = data.responseJSON.message.code;
if (messageCode === "DIGX_FL_059") {
self.showMessages(data, null, null, function () {
history.back();
window.onbeforeunload = null;
});
return true;
} else {
self.showMessages(null, [data.responseJSON.message.detail], 'ERROR');
return true;
}
}
}
//message
if (data.status.message != null && data.status.message.relatedMessage != null &&
data.status.message.relatedMessage != null &&
data.status.message.relatedMessage.length > 0 &&
data.status.message.relatedMessage[0] != null &&
data.status.message.relatedMessage[0].code != 'DIGX_SCB_BPT_00') {
self.showMessages(null, [data.status.message.relatedMessage[0].detail], 'ERROR');
return true;
}
return false;
};
self.setDataDTOApproval = function (myself, source) {
if (source) {
myself.isLoadedForApproval(false);
myself.d(source);
myself.isLoadedForApproval(true);
} else {
console.log('===== ' + myself.loadComponentName() + '-KHONG CO DATA =====');
}
};
self.dictAdd = function (dicarray, p_name, p_value) {
var obj = ko.toJS(dicarray);
if (obj == null || obj[0] == null || obj[0]['nameValuePairDTOArray'] == null) {
console.log('nameValuePairDTOArray is null');
return obj;
}
var field = {
"name": p_name, "value": p_value
};
//console.log('nameValuePairDTOArray:' + obj[0]['nameValuePairDTOArray'].length);
if ((obj[0]['nameValuePairDTOArray'][0]['name'] == null || obj[0]['nameValuePairDTOArray'][0]['name'] === '') &&
(obj[0]['nameValuePairDTOArray'][0]['value'] == null || obj[0]['nameValuePairDTOArray'][0]['value'] === '')) {
obj[0]['nameValuePairDTOArray'][0]['name'] = p_name;
obj[0]['nameValuePairDTOArray'][0]['value'] = p_value;
return obj;
}
//console.log('nameValuePairDTOArray:' + obj[0]['nameValuePairDTOArray'].length);
//them 1 cai khac. Copy tu cai thu 0
// obj[0]['nameValuePairDTOArray'].push(obj[0]['nameValuePairDTOArray'][0]);
// var lastposition = obj[0]['nameValuePairDTOArray'].length - 1;
// obj[0]['nameValuePairDTOArray'][lastposition]['name'] = p_name;
// obj[0]['nameValuePairDTOArray'][lastposition]['value'] = p_value;
obj[0]['nameValuePairDTOArray'].push(field);
return obj;
}
self.dictGetValueByName = function (dicarray, p_name) {
var obj = ko.toJS(dicarray);
if (obj == null || obj[0] == null || obj[0]['nameValuePairDTOArray'] == null) {
console.log('nameValuePairDTOArray is null');
return obj;
}
for (var i = 0; i < obj[0]['nameValuePairDTOArray'].length; i++) {
if (obj[0]['nameValuePairDTOArray'][i]['name'] === p_name || obj[0]['nameValuePairDTOArray'][i]['genericName'] === p_name) {
return obj[0]['nameValuePairDTOArray'][i]['value'];
}
}
}
//Khai bao nut back
self.callBackPage = function (transname, currentpage) {
//var obj1 = '{"flowPage":{"transactionNames":[{"card-lock-unlock":[{"currentPage":"card-lock","backPage":"scb-cards","headerTitleBackPage":"Thẻ","baseModel":""},{"currentPage":"scb-cards-review","backPage":"card-lock","headerTitle":"Khóa/Mở khóa thẻ","baseModel":""},{"currentPage":"scb-cards-result","backPage":"card-lock-unlock","headerTitle":"Khóa/Mở khóa thẻ","baseModel":""}]}]}}';
//var obj = cobj1);
self.methodAction = ko.observable(jsonCallBack);
//self.methodAction = JSON.parse(jsonCallBack); //ko.util.toJs();
self.methodList = ko.observableArray(self.methodAction().flowPage.transactionNames);
//Object.entries(ii)[0][0]
//Object.entries(ii)[0][1] : 3 phan tu
//Object.entries(ii)[0][1][0].backPage
for (var i = 0; i < self.methodList().length; i++) {
var keyname = Object.entries(self.methodList()[i])[0][0]; //Object.keys(self.methodList()[i]);
if (keyname === transname) {
var ii = self.methodList()[i];
var mangcon3pt = Object.entries(ii)[0][1];
//chay for de quet cac page trong chuc nang nay
for (var y = 0; y < mangcon3pt.length; y++) {
if (mangcon3pt[y].currentPage === currentpage) {
rootParams.baseModel.componentName = mangcon3pt[y].backPage;
rootParams.baseModel.componentParams = self;
rootParams.dashboard.headerName(mangcon3pt[y].headerTitle);
rootParams.dashboard.loadComponent(rootParams.baseModel.componentName, {}, rootParams.baseModel.componentParams);
}
}
}
}
};
self.remove_vn_accents = function (str) {
if (typeof str != 'string')
return null;
str = str.replace(/(á|à|ả|ã|ạ|ă|ắ|ằ|ẳ|ẵ|ặ|â|ấ|ầ|ẩ|ẫ|ậ)/g, 'a');
str = str.replace(/(A|Á|À|Ả|Ã|Ạ|Ă|Ắ|Ằ|Ẳ|Ẵ|Ặ|Â|Ấ|Ầ|Ẩ|Ẫ|Ậ)/g, 'A');
str = str.replace(/đ/g, 'd');
str = str.replace(/Đ/g, 'D');
str = str.replace(/(é|è|ẻ|ẽ|ẹ|ê|ế|ề|ể|ễ|ệ)/g, 'e');
str = str.replace(/(É|È|Ẻ|Ẽ|Ẹ|Ê|Ế|Ề|Ể|Ễ|Ệ)/g, 'E');
str = str.replace(/(í|ì|ỉ|ĩ|ị)/g, 'i');
str = str.replace(/(Í|Ì|Ỉ|Ĩ|Ị)/g, 'I');
str = str.replace(/(ó|ò|ỏ|õ|ọ|ô|ố|ồ|ổ|ỗ|ộ|ơ|ớ|ờ|ở|ỡ|ợ)/g, 'o');
str = str.replace(/(Ó|Ò|Ỏ|Õ|Ọ|Ô|Ố|Ồ|Ổ|Ỗ|Ộ|Ơ|Ớ|Ờ|Ở|Ỡ|Ợ)/g, 'O');
str = str.replace(/(ú|ù|ủ|ũ|ụ|ư|ứ|ừ|ử|ữ|ự)/g, 'u');
str = str.replace(/(Ú|Ù|Ủ|Ũ|Ụ|Ư|Ứ|Ừ|Ử|Ữ|Ự)/g, 'U');
str = str.replace(/(ý|ỳ|ỷ|ỹ|ỵ)/g, 'y');
str = str.replace(/(Ý|Ỳ|Ỷ|Ỹ|Ỵ)/g, 'Y');
return str;
};
// ======================= SCB ========================
if (window.cordova && window.device) {
self.iPhoneX = window.device.model.includes('iPhone10,3') || window.device.model.includes('iPhone10,6');
}
/**
* Knockout Observable which returns boolean true/false depending on whether the screen is large and above.
* @instance
* @memberof BaseKOModel
* @alias large
* @type {Observable.}
*/
self.large = oj.ResponsiveKnockoutUtils.createMediaQueryObservable(oj.ResponsiveUtils.getFrameworkQuery(
oj.ResponsiveUtils.FRAMEWORK_QUERY_KEY.LG_UP));
/**
* Knockout Observable which returns boolean true/false depending on whether the screen is medium sized only.
* @instance
* @memberof BaseKOModel
* @alias medium
* @type {Observable.}
*/
self.medium = oj.ResponsiveKnockoutUtils.createMediaQueryObservable(oj.ResponsiveUtils.getFrameworkQuery(
oj.ResponsiveUtils.FRAMEWORK_QUERY_KEY.MD_ONLY));
/**
* Knockout Observable which returns boolean true/false depending on whether the screen is small only.
* @instance
* @memberof BaseKOModel
* @alias small
* @type {Observable.}
*/
self.small = oj.ResponsiveKnockoutUtils.createMediaQueryObservable(oj.ResponsiveUtils.getFrameworkQuery(
oj.ResponsiveUtils.FRAMEWORK_QUERY_KEY.SM_ONLY));
/**
* Knockout Observable which returns boolean true/false depending on whether the screen is extra large and above.
* @instance
* @memberof BaseKOModel
* @alias xl
* @type {Observable.}
*/
self.xl = oj.ResponsiveKnockoutUtils.createMediaQueryObservable(oj.ResponsiveUtils.getFrameworkQuery(
oj.ResponsiveUtils.FRAMEWORK_QUERY_KEY.XL_UP));
/**
* Create a key in knockout object for mapping plugin.
* @type {Object}
*/
require(["knockout-mapping"], function (mapping) {
ko.mapping = mapping;
});
/**
* The current language of the page as determined from navigator or user requested value picked from sessionStorage.
* @type {String}
* @member
*/
// eslint-disable-next-line no-storage/no-browser-storage
var language = sessionStorage.getItem("user-locale") || document.getElementsByTagName("html")[0].getAttribute("lang") || "en";
/**
* Set the language [lang]{@linkcode BaseKOModel~lang} as locale for oj.Config so that localization for Oracle JET is properly set.
* @type {Object}
*/
oj.Config.setLocale(language, function () {
var direction = Constants.RTL_LOCALES.indexOf(language) === -1 ? "ltr" : "rtl";
document.getElementsByTagName("html")[0].setAttribute("dir", direction);
document.getElementsByTagName("html")[0].setAttribute("lang", language);
});
/**
* Array to store the list of authorized components for a particular user which will be consumed by
* [knockout custom component loader]{@linkcode BaseKOModel~componentCustomLoader}.
* @instance
* @memberof BaseKOModel
* @alias authorisedCompoList
* @type {Observable.}
*/
self.authorisedCompoList = ko.observableArray([]);
/**
* Observable to store the time at which the last middleware request was fired.
* Declared inside [BaseKOModel]{@linkcode BaseKOModel} but is set in [service base]{@linkcode BaseService~genericCompleteHandler}.
* @instance
* @memberof BaseKOModel
* @alias lastUpdatedTime
* @type {Observable.}
*/
self.lastUpdatedTime = ko.observable();
/**
* Knockout Custom Component loader to selectively load only those components which are specified in [authorisedCompoList]{@linkcode BaseKOModel#authorisedCompoList}.
* For more details, refer the [official KnockoutJS documentation]{@link http://knockoutjs.com/documentation/component-loaders.html#custom-component-loader}.
* @type {Object}
* @member
*/
var componentCustomLoader = {
loadComponent: function (name, componentConfig, callback) {
if (componentConfig.basePath === "components" && Extensions.components.indexOf(componentConfig.module + "/" + name) > -1) {
componentConfig.basePath = "extensions/components";
}
else if (componentConfig.basePath === "framework/elements" && Extensions.components.indexOf(componentConfig.module + "/" + name) > -1) {
componentConfig.basePath = "extensions/elements";
}
var componentPath = componentConfig.basePath + "/" + componentConfig.module + "/" + name + "/ko/bindings/" + name + "-bindings";
ko.components.defaultLoader.loadComponent(name, {
require: componentConfig.compLoader ? componentConfig.compLoader(name, componentConfig, componentPath) : componentPath
}, callback);
}
};
/**
* Set the custom loader [componentCustomLoader]{@linkcode BaseKOModel~componentCustomLoader} as the primary Knockout component loader.
* @type {Boolean}
*/
ko.components.loaders.unshift(componentCustomLoader);
/**
* Using deferUpdates as true reduces the UI clutter. Notifications happen asynchronously, immediately after the current task and generally before any UI redraws.
* But you should take care because it will break code that depends on synchronous updates or on notification of intermediate values. Recommended workaround is using ko.tasks.runEarly().
* @type {Boolean}
*/
ko.options.deferUpdates = true;
/**
* The function to wrap a variable as an observable.
* In case the value is already an observable, then the variable is not wrapped.
* @instance
* @function checkAndBindObservable
* @memberof BaseKOModel
* @param {Object} attr - The variable whose which has to be wrapped as an observable.
* @param {Object} value - The default value of to initialize the variable with in case it is undefined.
* @returns {Observable.<*>} - The variable wrapped as an observable.
*/
self.checkAndBindObservable = function (attr, value) {
return ko.observable(ko.utils.unwrapObservable(attr) || value || "");
};
/**
* This function is used to register a knockout component.
* Once a knockout component is registered, it can be used as a reusable template wherever required,
* wherein both the component's template and view model shall be loaded.
*
* @function registerComponent
* @instance
* @param {String} componentId - The name of the component.
* @param {object} moduleId - The module name the component is a part of.
* @param {object} compLoader - Callback for component loader to be used while component registration.
* @memberof BaseKOModel
* @return {void}
*/
self.registerComponent = function (componentId, moduleId, compLoader) {
var basePath = "components";
if (!ko.components.isRegistered(componentId)) {
ko.components.register(componentId, {
basePath: basePath,
module: moduleId,
compLoader: compLoader
});
}
};
/**
* This function is used to register a OBDX core elements.
* Once a knockout component is registered, it can be used as a reusable template wherever required,
* wherein both the component's template and view model shall be loaded.
*
* @function registerElement
* @instance
* @param {String} components - The name of the component.
* @param {object} [moduleId = 'api'] - The module name the component is a part of.
* @memberof BaseKOModel
* @return {void}
*/
self.registerElement = function (components, moduleId) {
var basePath = "framework/elements";
if (!Array.isArray(components)) components = [components];
components.forEach(function (componentId) {
if (!ko.components.isRegistered(componentId)) {
ko.components.register(componentId, {
basePath: basePath,
module: moduleId || "api"
});
}
});
};
/**
* Converts a javascript object to JSON string implemenation.
* Uses [trimPayload]{@linkcode BaseModel#trimPayload} as replacer function for JSON.stringify.
* @function removeTempAttributes
* @instance
* @memberof BaseKOModel
* @param {Object} data The javascript object to be converted.
* @return {String} JSON string is returned.
*/
self.removeTempAttributes = function (data) {
return JSON.stringify(ko.toJS(data), self.trimPayload);
};
self.messages = ko.observableArray();
/**
* This function is used to display the server side error message or devloper configured messages.
* Registers and opens a new component message-box for displaying the error messages.
* @function showMessages
* @memberof BaseKOModel
* @instance
* @param {Object} jqXHR - The jqXHR object of the ajax call.
* Used to extract server sent error messages by [service base]{@linkcode BaseService~genericCompleteHandler}.
* @param {Array.} errorsMessages - Sets the custom error message(s) to be thrown.
* The server needn't throw any error, set this property to thow user customized message(s).
Pass null as first argument in such cases.
* @param {String} messageType - The type of message intended, is compulsory if custom message is being thrown.
* Can assume following values,
* ERROR, INFO, SUCCESS or NOTIFICATION.
* @param {Function} [onClose] - Function to be called when message box opened by this function is closed.
* @returns {void}
*/
self.showMessages = function (jqXHR, errorsMessages, messageType, onClose) {
self.messages.push({
response: jqXHR,
errors: errorsMessages,
type: messageType,
onClose: onClose,
id: Math.ceil((Math.random() * 9999999999) + 1)
});
};
self.language = language;
/**
* Generic method to invoke authorization screen (OTP Screen, HOTP Screen, etc).
* @param {Object} jqXHR The jqXHR object of the ajax call.
* @param {Object} context The context of the request to be passed forward.
* @param {Function} requestFunction The request function to invoke the middleware request again with authorization credentials.
* Can be [fireAjax]{@linkcode BaseService#fireAjax} or [getNonceForServiceInstance]{@linkcode BaseService~getNonceForServiceInstance}.
* @param {Function} successHandlerFunction The success handler of the middleware request.
* @returns {void}
*/
self.showAuthScreen = function (jqXHR, context, requestFunction, successHandlerFunction) {
var authViewModel = {
baseModel: self,
serverResponse: jqXHR,
currentContext: context,
fireRequest: requestFunction,
originalSuccess: successHandlerFunction,
registerComponent: self.registerComponent,
currentIdCount: self.currentIdCount,
incrementIdCount: self.incrementIdCount
};
self.registerComponent("generic-authentication", "base-components");
$("#authScreenWindow").remove();
var parent = document.createElement("div");
parent.setAttribute("data-bind", "component : {name: \"generic-authentication\", params:{rootModel: $data, id : \"authScreenWindow\"}}");
parent.id = "authScreenWindow";
$("main.container").append(parent);
$("div.primarycontent").hide();
ko.applyBindings(authViewModel, document.getElementById("authScreenWindow"));
};
/**
* Switch the language of the application.
* @function setLocale
* @instance
* @memberof BaseKOModel
* @param {String} newLanguage - The language to be set.
* Use valid ISO 639-1 language code.
* @returns {void}
*/
self.setLocale = function (newLanguage) {
if (language !== newLanguage) {
// eslint-disable-next-line no-storage/no-browser-storage
sessionStorage.setItem("user-locale", newLanguage);
window.location.reload();
}
};
function addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
};
/**
* This method used for getting server date time on user desired format
* @function getDate
* @instance
* @memberof BaseKOModel
* @param {String} [dateType] - Desired format of server date.
* Use valid ISO 639-1 language code.
* @returns {Date}
*/
self.getDate = function (dateType) {
var date = new Date(Constants.currentServerDate.getTime());
if (Constants.timezoneOffset) {
date.setMinutes(date.getMinutes() + date.getTimezoneOffset() + (-1 * Constants.timezoneOffset));
}
switch (dateType) {
case "DATE_TIME":
return date;
case "DATE_TIME_PRINF":
return addZero(date.getDate()) + '/' + addZero(date.getMonth()+1) + '/' + date.getFullYear() + ' ' + addZero(date.getHours())+ ':'+ addZero(date.getMinutes());
default:
return new Date(date.toDateString());
}
};
/**
* Returns the ISO 639-1 of the current language of the application.
* @function getLocale
* @instance
* @memberof BaseKOModel
* @return {String} The ISO 639-1 code of the language.
*/
self.getLocale = function () {
return oj.Config.getLocale();
};
/**
* Extends the formatter instance returned from dashboard-binding.
* @param {Formatter} Formatter Instance of {@linkcode Formatter}.
* @returns {void}
*/
self.setFormatter = function (Formatter) {
ko.utils.extend(self, Formatter);
};
/**
* The global error handler for RequireJS.
* To detect errors that are not caught by local errbacks, this overriden implemenation of requirejs.onError() is used.
* @function onError
* @inner
* @callback
* @memberof BaseKOModel
* @param {Object} err The error object returned by RequireJS.
* @returns {void}
*/
require.onError = function (err) {
if (console && console.error) console.error(err);
if (err.requireType === "timeout" || err.requireType === "scripterror") {
self.showMessages(null, [Locale.error], "ERROR", function () {
window.location.reload();
});
}
};
};
/**
* Holds the instance of [BaseKOModel]{@linkcode BaseKOModel}
* @memberof module:baseModel
* @inner
* @type {BaseKOModel}
*/
var instance;
return {
/**
* Get the base model instance. Checks [instance]{@linkcode module:baseModel~instance} for instance.
* @function getInstance
* @memberof module:baseModel
* @static
* @returns {BaseKOModel} The base service instance.
*/
getInstance: function () {
if (!instance) {
instance = new BaseKOModel();
}
return instance;
}
};
});